Introducción a Bison
Fuente: Manual oficial de bison
Bison es una versión más de nueva de yacc, que es retrocompatible y permite exportar parsers en java. Bison trabaja con archivos .y
que son casi idénticos a los de yacc.
fuente)#
Estructura (%{ Prologue%}
Bison declarations
%%Grammar rules%%
Epilogue
El prólogo y el epílogo permiten introducir código java antes o después del parser generado por bison. No usaremos estas secciones. Las otras se describen brevemente a continuación.
fuente)#
Declaraciones bison (Son configuraciones generales sobre el parser que Bison generará.
%language "Java"
el parser emitido es código java%define api.parser.class {Calc}
Define el nombre de la clase parser generada (en este casoCalc
).%define api.parser.public
Hace que la visibilidad de la clase del parser sea pública%define package {ar.uba.fi.compiladores.parte5}
Package de la clase generada.%define api.value.type {Number}
Define el tipo de los valores semánticos. Un valor semántico es el resultado de la aplicación del token. En el caso de la calculadora, este tipo esNumber
. En el caso del intérprete de lisp construido en la parte 4, estos son valores de tipoObject
. Un parser que no procese el programa a medida que lo analiza podría devolver una clase que represente un nodo del ábrol de sintaxis abstracto. Un compilador podría devolver una porción del programa compilado.%token L_PAREN
: define un símbolo terminal (en este caso,L_PAREN
).%code { <código java> }
: codigo java inyectado en la clase generada, lo cual permite agregar propiedades y métodos.%code imports { <imports java> }
: Permite importar clases para usarlos en el código de la clase generada%code init { <código java> }
: Código que se ejecuta en el constructor del parser generado.
fuente)#
Reglas de derivación (La regla
Se escribe como:
factor: L_PAREN exp R_PAREN | NUMBER ;
Para capturar la sintaxis, hay que escribir acciones, que son código java entre corchetes, de la siguiente manera:
factor: L_PAREN exp R_PAREN { $$=$2; System.out.printLn("("+$2+")");}| NUMBER { $$=$1; System.out.printLn("number!" + $1); };
Este código java es "especial". Se agregan las siguientes variables:
$$
: valor semántico que devuelve esta regla$n
donden
es un número: devuelve el valor semántico deln
-avo token producido por la regla.
#
Integración del parser generado por bison#
Integración con mavenEn el pom.xml
del lab 2 se agregó una etapa a la compilación que llama al comando bison
para cada uno de los archivos .y
del proyecto, y almacena los parser java generados en lab2/target/generated-sources/bison
.
danger
Cuando un archivo .y
está mal escrito, la generación falla silenciosamente. Es necesario correr la tarea maven compile
y verificar en los logs si el archivo se generó mal.
El comando bison
está instalado en el devcontainer
. De no usar el devcontainer
, será necesario instalarlo.
#
Integración con el resto del códigoLa clase parser generada recibe como parámetro de su constructor un lexer. Este lexer debe implementar una interfaz que está escrita dentro del parser. Es decir, si el parser se llama Calc
, la interfaz del lexer a implementar es Calc.Lexer
. Métodos de la interfaz:
yylex()
: Devuelve el tipo del siguiente token. Este tipo es unint
. La interfazLexer
define constantes estáticasint
, cada una de las cuales tiene el nombre de uno de los símbolos terminales, y cuyo valor es elint
correspondiente.getLVal()
: Devuelve el valor semántico del último token devuelto poryylex()
. Si el mismo no tiene valor semántico (como en el caso de(
ó+
), no se debe arrojar un error.yyerror(msg)
: Emite un error.